﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace ExcelImport
{
    public static class DataTableExtension
    {
        public static List<T> ToList<T>(this DataTable dt, ImportTable importTable) where T : class, new()
        {
            var type = typeof(T);

            var importProperties = importTable.ImportProperties.Where(p => p.Ordinal.HasValue);

            List<T> list = new List<T>();

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                T t = new T();

                var row = dt.Rows[i];

                foreach (var importProperty in importProperties)
                {
                    try
                    {
                        object value = row.GetValue(importProperty.PropertyName, importProperty.DataType);

                        if (value is DBNull || value == null) continue;

                        importProperty.PropertyInfo.SetValue(t, value);
                    }
                    catch (Exception ex)
                    {
                        throw new ApplicationException($"第{i + 1}行,将{importProperty.HeaderName}转换为{importProperty.DataType.Name}时发生错误,请检查数据类型是否正确", ex);
                    }
                }

                list.Add(t);
            }

            return list;
        }

        public static object GetValue(this DataRow row, string columnName, Type dataType)
        {
            if (_converters.TryGetValue(dataType, out var converter))
            {
                return converter.Invoke(row[columnName]);
            }
            throw new NotSupportedException($"暂不支持的数据类型{dataType.Name}");
        }

        private static Dictionary<Type, Func<object, object>> _converters = new Dictionary<Type, Func<object, object>>();

        static DataTableExtension()
        {
            _converters.Add(typeof(string), StringConverter);
            _converters.Add(typeof(int), IntConverter);
            _converters.Add(typeof(int?), IntConverter);
            _converters.Add(typeof(float), FloatConverter);
            _converters.Add(typeof(float?), FloatConverter);
            _converters.Add(typeof(double), DoubleConverter);
            _converters.Add(typeof(double?), DoubleConverter);
            _converters.Add(typeof(decimal), DecimalConverter);
            _converters.Add(typeof(decimal?), DecimalConverter);
            _converters.Add(typeof(DateTime), DateConverter);
        }

        public static object StringConverter(object value)
        {
            return value?.ToString();
        }

        public static object IntConverter(object value)
        {
            if (value == null) return value;
            return int.Parse(value.ToString());
        }

        public static object FloatConverter(object value)
        {
            if (value == null) return value;
            return float.Parse(value.ToString());
        }

        public static object DoubleConverter(object value)
        {
            if (value == null) return value;
            return double.Parse(value.ToString());
        }

        public static object DateConverter(object value)
        {
            if (value == null) return value;
            return DateTime.Parse(value.ToString());
        }

        public static object DecimalConverter(object value)
        {
            if (value == null) return value;
            return decimal.Parse(value.ToString());
        }
    }
}